#include "../include/MyLogger.hpp"
#include <iostream>
#include <sstream>
#include <iomanip>
#include <chrono>
#include <filesystem>
namespace jpx
{
MyLogger & MyLogger::get_instance()
{
    static MyLogger instance;
    return instance;
}
MyLogger::~MyLogger()
{
    shutdown();
}
//初始化日志系统
std::once_flag logger_init_flag;
bool MyLogger::initialize_logger(const string & configFile)
{
    bool flag = false;
    std::call_once(jpx::logger_init_flag,[&](){
                flag = MyLogger::get_instance().initialize(configFile);
                   });
    return flag;
}
bool MyLogger::initialize(const string & configfile,const string & configure)
{
    if(_initialized)
    {
        log_warn("Logger already initialized", "MyLogger::initialize");
        return true;
    }
    try{
        if(!configure.empty())
        {
        Configuration::get_Instance().load_from_file(configure);
        }
        if(!configfile.empty())
        {
            return initialize_with_config(configfile);
        }else
        {
            return initialize_with_defaultConfig();
        }
    }catch(const exception & e)
    {
        cerr << "Logger initialization failed: " << e.what() << endl;
        return false;
    }
}
bool MyLogger::initialize_with_config(const string & configfile)
{
    try{
        PropertyConfigurator::configure(configfile);
        //初始化不同级别的Logger
        _logger = &Category::getInstance("UserOperationLogger");
        _infoLogger = &Category::getInstance("InfoLogger");
        _debugLogger = &Category::getInstance("DebugLogger");
        _warnLogger = &Category::getInstance("WarnLogger");
        _errorLogger = &Category::getInstance("ErrorLogger");
        _initialized = true;
        log_info("Logger initialize with config file: " + configfile, "MyLogger::initialize_with_config");
        //cout << "Logger initialized with config file: " << configfile << endl;
        return true;
    }catch(const ConfigureFailure & e)
    {
        //cerr << "Failed to configure logger with file" << configfile << "." << e.what() << endl;
        string errorMsg = "Failed to configure logger with file " + configfile + ": " + string(e.what());
        log_error(errorMsg, "MyLogger::initialize_with_config");
        return initialize_with_defaultConfig();//回退到默认配置
    }
}
bool MyLogger::initialize_with_defaultConfig()
{
    try{
        //为每个级别创建独立的Appender
        //Debug Appender
        RollingFileAppender * debugAppender = new RollingFileAppender(
                                                                      "debugAppender",
                                                                      "log/debug.log",
                                                                      //Configuration::get_Instance().get_string("debugPath"),
                                                                      5242880,
                                                                      5
                                                                     );
        PatternLayout * debugLayout = new PatternLayout();
        debugLayout->setConversionPattern("%d{%Y-%m-%d %H:%M:%S.%l} [%p] %c - %m%n");
        debugAppender->setLayout(debugLayout);

        //Info Appender
        RollingFileAppender * infoAppender = new RollingFileAppender(
                                                                     "infoAppender",
                                                                     "log/info.log",
                                                                     //Configuration::get_Instance().get_string("infoPath"),
                                                                     5242880,
                                                                     5
                                                                    );
        PatternLayout * infoLayout = new PatternLayout();
        infoLayout->setConversionPattern("%d{%Y-%m-%d %H:%M:%S.%l} [%p] %c - %m%n");
        infoAppender->setLayout(infoLayout);

        //Warn Appender
        RollingFileAppender * warnAppender = new RollingFileAppender(
                                                                     "warnAppender",
                                                                     "log/warn.log",
                                                                     //Configuration::get_Instance().get_string("warnPath"),
                                                                     5242880,
                                                                     5
                                                                    );
        PatternLayout * warnLayout = new PatternLayout();
        warnLayout->setConversionPattern("%d{%Y-%m-%d %H:%M:%S.%l} [%p] %c - %m%n");
        warnAppender->setLayout(warnLayout);

        //Error Appender
        RollingFileAppender * errorAppender = new RollingFileAppender(
                                                                      "errorAppender",
                                                                      "log/error.log",
                                                                     // Configuration::get_Instance().get_string("errorPath"),
                                                                      5242880,
                                                                      5
                                                                     );
        PatternLayout * errorLayout = new PatternLayout();
        errorLayout->setConversionPattern("%d{%Y-%m-%d %H:%M:%S.%l} [%p] %c - %m%n");
        errorAppender->setLayout(errorLayout);

        //用户操作文件 Appender
        RollingFileAppender * userOpFileAppender = new RollingFileAppender(
                                                                           "fileAppender",
                                                                           "log/user_operations.log",
                                                                           //Configuration::get_Instance().get_string("user_operationsPath"),
                                                                           5242880,
                                                                           5
                                                                          );
        PatternLayout * userOpFileLayout = new PatternLayout();
        userOpFileLayout->setConversionPattern("%d{%Y-%m-%d %H:%M:%S.%l} [%p] %m%n");
        userOpFileAppender->setLayout(userOpFileLayout);
        //控制台Appender
        OstreamAppender * consoleAppender = new OstreamAppender(
                                                                "consoleAppender",
                                                                &cout
                                                               );
        PatternLayout * consoleLayout = new PatternLayout();
        consoleLayout->setConversionPattern("%d{%H:%M:%S} [%p] %m%n");
        consoleAppender->setLayout(consoleLayout);

        //初始化各个logger
        _debugLogger = &Category::getInstance("DebugLogger");
        _debugLogger->setAdditivity(false);
        _debugLogger->setPriority(Priority::DEBUG);
        _debugLogger->addAppender(debugAppender);
        _debugLogger->addAppender(consoleAppender);

        _infoLogger = &Category::getInstance("InfoLogger");
        _infoLogger->setAdditivity(false);
        _infoLogger->setPriority(Priority::INFO);
        _infoLogger->addAppender(infoAppender);
        _infoLogger->addAppender(consoleAppender);

        _warnLogger = &Category::getInstance("WarnLogger");
        _warnLogger->setAdditivity(false);
        _warnLogger->setPriority(Priority::WARN);
        _warnLogger->addAppender(warnAppender);
        _warnLogger->addAppender(consoleAppender);

        _errorLogger = &Category::getInstance("ErrorLogger");
        _errorLogger->setAdditivity(false);
        _errorLogger->setPriority(Priority::ERROR);
        _errorLogger->addAppender(errorAppender);
        _errorLogger->addAppender(consoleAppender);

        //用户操作logger
        _logger = &Category::getInstance("UserOperationLogger");
        _logger->setAdditivity(false);
        _logger->setPriority(Priority::INFO);
        _logger->addAppender(userOpFileAppender);
        _logger->addAppender(consoleAppender);

        //系统日志
        RollingFileAppender * systemAppender = new RollingFileAppender(
                                                                       "rootAppender",
                                                                       "log/system.log",
                                                                       //Configuration::get_Instance().get_string("systemPath"),
                                                                       5242880,
                                                                       3
                                                                      );
        PatternLayout * systemLayout = new PatternLayout();
        systemLayout->setConversionPattern("%d{%Y-%m-%d %H:%M:%S.%l} [%p] %c: %m%n");
        systemAppender->setLayout(systemLayout);

        Category& rootCategory = Category::getRoot();
        rootCategory.setAdditivity(false);
        rootCategory.setPriority(Priority::DEBUG);
        rootCategory.addAppender(systemAppender);

        _initialized = true;
        log_info("Logger initialize with default configuration", "MyLogger::initialize_with_defaultConfig");
        return true;
    }catch(const exception & e)
    {
        string errorMsg = "Failed to initialize logger with default config: " + string(e.what());
        //cerr << "Failed to initialized logger with default config: " << e.what() << endl;
        log_error(errorMsg, "MyLogger::initialize_with_defaultConfig");
        return false;
    }
}
//获取操作类型字符串
string MyLogger::get_operation_typeString(OperationType onType)
{
    switch(onType)
    {
    case OperationType::USER_REGISTER:
        return "USER_REGISTER";
    case OperationType::USER_LOGIN:
        return "USER_LOGIN";
    case OperationType::VIEW_CAMERA_INFO:
        return "VIEW_CAMERA_INFO";
    default:
        return "UNKNOWN";
    }
}
//记录用户操作
void MyLogger::log_user_operation_by_user(OperationType opType,
                                  const string & userId,
                                  const string & username,
                                  const string & details,
                                  const string & ipAddress)
{
    if(!_initialized || !_logger)
    {
        cerr << "Logger not initialized!" << endl;
        return;
    }
    try{
        log4cpp::Category * userLogger = get_or_create_user_logger(userId);
        ostringstream oss;
        oss << "OPERATION: " << get_operation_typeString(opType)
            << " | USER: " << username;
        if(!ipAddress.empty())
        {
            oss << " | IP: " << ipAddress;
        }
        if(!details.empty())
        {
            oss << " | DETAILS: " << details;
        }
        userLogger->info(oss.str());
    }catch(const exception & e)
    {
        cerr << "Failed to log operation: " << e.what() << endl;
    }
}
//记录用户注册操作
void MyLogger::log_user_register_by_user(const string & userId,
                                         const string & username,
                                         const string & email,
                                         const string & additionalInfo,
                                         const string & ipAddress)
{
    ostringstream details;
    details << "User registered successfully";

    if(!email.empty())
    {
        details << " | Email: " << email;
    }
    if(!additionalInfo.empty())
    {
        details << " | Info: " << additionalInfo;
    }
    log_user_operation_by_user(OperationType::USER_REGISTER, userId ,username, details.str(), ipAddress);
}

//记录用户操作
void MyLogger::log_user_login_by_user(const string & userId,
                                      const string & username,
                              const string & ipAddress,
                              const string & userAgent)
{
    ostringstream details;
    details << "User logged in successfully";

    if(!userAgent.empty())
    {
        details << " | UserAgent: " << userAgent; 
    }
    log_user_operation_by_user(OperationType::USER_LOGIN, userId ,username, details.str(), ipAddress);
}
//记录查看摄像头信息操作
void MyLogger::log_view_cameraInfo_by_user(const string & userId,
                                           const string & username,
                                   const string & cameraId,
                                   const string & cameraName,
                                   const string & ipAddress)
{
    ostringstream details;
    details << "CameraID: " << cameraId;

    if(!cameraName.empty())
    {
        details << " | CameraName: " << cameraName;
    }
    log_user_operation_by_user(OperationType::VIEW_CAMERA_INFO, userId ,username, details.str(), ipAddress);
}
void MyLogger::log_debug(const string & message,
                         const string & location,
                         int lineNumber,
                         const string & additionalInfo)
{
    if(!_initialized || !_debugLogger)
    {
        cerr << "Logger not initialized!" << endl;
        return;
    }
    try{
        ostringstream oss;
        if(!location.empty()) oss << "[Function: " << location << "]";
        if(lineNumber != 0) oss << ", Line: " << lineNumber;
        oss << message;
        if(!additionalInfo.empty()) oss << " | " << additionalInfo;
        _debugLogger->debug(oss.str());
    }catch(const exception & e)
    {
        cerr << "Failed to log debug: " << string(e.what()) << endl;
    }
}
void MyLogger::log_info(const string & message,
                        const string & location,
                        int lineNumber,
                        const string & additionalInfo)
{
    if(!_initialized || !_infoLogger)
    {
        cerr << "Logger not initialized!" << endl;
        return;
    }
    try{
        ostringstream oss;
        if(!location.empty()) oss << "[Function: " << location << "]";
        if(lineNumber != 0) oss << ", Line: " << lineNumber;
        oss << message;
        if(!additionalInfo.empty()) oss << " | " << additionalInfo;
        _infoLogger->info(oss.str());
    }catch(const exception & e)
    {
        cerr << "Failed to log info: " << string(e.what()) << endl;
    }
}
void MyLogger::log_warn(const string & message,
                        const string & location,
                        int lineNumber,
                        const string & additionalInfo)
{
    if(!_initialized || !_warnLogger)
    {
        cerr << "Logger not initialized!" << endl;
        return;
    }
    try{
        ostringstream oss;
        if(!location.empty()) oss << "[Function: " << location << "]";
        if(lineNumber != 0) oss << ", Line: " << lineNumber;
        oss << message;
        if(!additionalInfo.empty()) oss << " | " << additionalInfo;
        _warnLogger->warn(oss.str());
    }catch(const exception & e)
    {
        cerr << "Failed to log warning: " << string(e.what()) << endl; 
    }
}
void MyLogger::log_error(const string & message,
                         const string & location,
                         int lineNumber,
                         const string & additionalInfo)
{
    if(!_initialized || !_errorLogger)
    {
        cerr << "Logger not initialized!" << endl;
        return;
    }
    try{
        ostringstream oss;
        if(!location.empty()) oss << "[Function: " << location << "]";
        if(lineNumber != 0) oss << ", Line: " << lineNumber;
        oss << message;
        if(!additionalInfo.empty()) oss << " | " << additionalInfo;
        _errorLogger->error(oss.str());
    }catch(const exception & e)
    {
        cerr << "Failed to log error: " << string(e.what()) << endl;
    }
}
log4cpp::Category * MyLogger::get_or_create_user_logger(const string & userId)
{
    lock_guard<mutex> lock(_userLoggersMutex);

    //如果已经存在，直接返回
    auto it = _userLoggers.find(userId);
    if(it != _userLoggers.end())
    {
        return it->second;
    }
    //创建新的用户日志器
    try{
        string appenderName = "UserAppender_" + userId;
        string fileName = "log/users/user_" + userId + ".log";

        //确保用户日志目录存在
        //std::filesystem::create_directories("../../../log/users");

        //创建用户专用的Appender
        RollingFileAppender * userAppender = new RollingFileAppender(
                                            appenderName.c_str(),
                                            fileName,
                                            5242880,
                                            5
                                                                    );
        PatternLayout * userLayout = new PatternLayout();
        userLayout->setConversionPattern("%d{%Y-%m-%d %H:%M:%S.%l} [%p] %m%n");
        userAppender->setLayout(userLayout);
        //创建用户专用的Category
        string categoryName = "UserLogger_" + userId;
        Category * userLogger = &Category::getInstance(categoryName);
        userLogger->setAdditivity(false);
        userLogger->setPriority(Priority::INFO);
        userLogger->addAppender(userAppender);

        //存储到映射中
        _userLoggers[userId] = userLogger;

        return userLogger;
    }catch(const exception & e)
    {
        cerr << "Failed to create user logger for " << userId << ": " << string(e.what()) << endl;
        return _logger;//回退到默认的用户操作日志器
    }
}
//关闭日志系统
void MyLogger::shutdown()
{
    if(_initialized)
    {
        lock_guard<mutex> lock(_userLoggersMutex);
        _userLoggers.clear();//清空映射
    }
        Category::shutdown();
        _initialized = false;
        _logger = nullptr;
        _debugLogger = nullptr;
        _infoLogger = nullptr;
        _warnLogger = nullptr;
        _errorLogger = nullptr;
        cout << "Logger shutdown completed" << endl;
    
}
}//end of namespace jpx
